package com.ilink.ilinkuser.controller;



import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import com.ilink.ilinkuser.config.OAuth2Properties;
import org.checkerframework.checker.units.qual.A;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.ilink.ilinkapi.dto.user.UserCASDTO;
import com.ilink.ilinkapi.dto.user.UserDTO;
import com.ilink.ilinkcommon.config.JwtProperties;
import com.ilink.ilinkcommon.domain.R;
import com.ilink.ilinkcommon.domain.User;
import com.ilink.ilinkcommon.domain.DTO.UserAuthenticationRequest;
import com.ilink.ilinkcommon.domain.VO.UserAuthenticationResponse;
import com.ilink.ilinkcommon.exception.UnauthorizedException;
import com.ilink.ilinkcommon.log.method.MethodLog;
import com.ilink.ilinkcommon.utils.HttpUtils;
import com.ilink.ilinkcommon.utils.JwtTokenProvider;
import com.ilink.ilinkcommon.utils.RSAUtils;
import com.ilink.ilinkcommon.utils.UserContext;
import com.ilink.ilinkuser.domain.VO.UserMetaResponse;
import com.ilink.ilinkuser.service.UserMessageExportService;
import com.ilink.ilinkuser.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * <h3>new-ilink-java-backend</h3>
 *
 * @author LiuZheng
 * @description <p>用户相关接口</p>
 * @date 2024-09-15 21:41
 **/

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    JwtProperties jwtProperties;

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private UserService userService;
    @Autowired
    private UserMessageExportService userMessageExportService;

    @Value("${ilink.web-url.local-frontend-ip}")
    private String localFrontendIp;

    @Value("${ilink.web-url.local-backend-ip}")
    private String localBackendIp;

    @Value("${ilink.web-url.bupt-auth}")
    private String buptAuthPrefix;

    @Value("${ilink.web-url.local-frontend-url}")
    private String localFrontendUrl;

    @Autowired
    private HttpUtils httpUtils;
    private final KeyPair keyPair = RSAUtils.generateKeyPair();
    @Autowired
    private UserApiKeysController userApiKeysController;

    private final OAuth2Properties oauth2Properties;

    // 通过构造器注入
    @Autowired
    public UserController(@Qualifier("OAuth2Properties") final OAuth2Properties oauth2Properties) throws NoSuchAlgorithmException {
        this.oauth2Properties = oauth2Properties;
    }

    @MethodLog()
    @GetMapping("/publicKey")
    public R getPublicKey() {
        return R.ok("", Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
    }

    @MethodLog("普通用户登录")
    @PostMapping("/login")
    public R login(@RequestBody UserDTO request, HttpServletResponse response) {
        try {
            String username = request.getUsername();
            User user = userService.loadUserByUsername(username);
            if (user == null) {
                return R.error("Username not found");
            }

            String decryptedPassword = RSAUtils.decrypt(request.getPassword(),
                    keyPair.getPrivate());

            //  校验用户名和密码
            if (!userService.checkUsernameAndPassword(username, decryptedPassword)) {
                return R.error("密码错误");
            }

            Map<String, String> accessTokenData = new HashMap<>();
            User new_user = (User) user;
//        accessTokenData.put("sub", new_user.getUserId());
            accessTokenData.put("sub", new_user.getUserId());
            accessTokenData.put("type", "access");
            long accessTokenExpiresIn = jwtProperties.getTokenTTL();
            String accessToken = jwtTokenProvider.createToken(accessTokenData,
                    accessTokenExpiresIn);

            Map<String, String> refreshTokenData = new HashMap<>();
            refreshTokenData.put("sub", new_user.getUserId());
            refreshTokenData.put("type", "refresh");
            long refreshTokenExpiresIn = jwtProperties.getRefreshTTL();
            String refreshToken = jwtTokenProvider.createToken(refreshTokenData,
                    refreshTokenExpiresIn);

            Map<String, Object> tokens = new HashMap<>();
            tokens.put("access_token", accessToken);
            tokens.put("refresh_token", refreshToken);
            tokens.put("token_type", "bearer");

            Cookie accessCookie = new Cookie("access_token_lf", accessToken);
            accessCookie.setPath("/");
            accessCookie.setHttpOnly(false);
            accessCookie.setSecure(false);
            accessCookie.setMaxAge(Math.toIntExact(jwtProperties.getTokenTTL()));
            response.addCookie(accessCookie);
            Cookie refreshCookie = new Cookie("refresh_token_lf", refreshToken);
            refreshCookie.setPath("/");
            refreshCookie.setHttpOnly(false);
            refreshCookie.setSecure(false);
            refreshCookie.setMaxAge(Math.toIntExact(jwtProperties.getRefreshTTL()));
            response.addCookie(refreshCookie);

            return R.ok("Login successful", tokens);
        } catch (Exception e) {
            e.printStackTrace();
            return R.error(e.getMessage());
        }
    }

    /*
     * 学校统一身份登录
     *
     * @param ticket
     * @return com.bupt.ilink.utils.R
     * @author liuzheng
     * @create 2024-09-10
     **/
    @MethodLog("学校统一登录")
    @PostMapping("/school_login")
    public R schoolLogin(@RequestBody UserDTO request, HttpServletResponse response) {
        String username = request.getUsername();
        String decryptedPassword = RSAUtils.decrypt(request.getPassword(), keyPair.getPrivate());
        String buptLoginUrl = buptAuthPrefix + "/v1/tickets";
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        params.add("username", username);
        params.add("password", decryptedPassword);

        //    发送请求到统一身份登录接口
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.valueOf(MediaType.APPLICATION_FORM_URLENCODED_VALUE));
        try {
            // 得到的是HTML结果，需要解析得到TGT
            String loginPost = httpUtils.post(buptLoginUrl, params, headers, String.class);
            // 解析得到的 TGT 查看是否正确
            // TGT 长期有效，后续可以基于缓存优化登录
            String TGT = loginPost;
            //  利用TGT获取ticket
            String buptGetTicketUrl = buptAuthPrefix + "/v1/tickets/" + TGT;
            params.clear();
            String localBackendUrl = "http://" + localBackendIp;
            params.add("service", localBackendUrl);
            String getTicketPost = httpUtils.post(buptGetTicketUrl, params, headers, String.class);
            log.info("获取得到的 ticket " + getTicketPost);
            //  解析得到tickets 需要判断是否正确
            String ticket = getTicketPost;
            String buptAuthUrl =
                    buptAuthPrefix + "/serviceValidate?service={service}&ticket={ticket}";
            params.clear();
            Map<String, Object> ticketParams = new HashMap<>();
            ticketParams.put("service", localBackendUrl);
            ticketParams.put("ticket", ticket);
            String numberAndTypeString = httpUtils.get(buptAuthUrl, ticketParams, String.class);
            Document document = DocumentHelper.parseText(numberAndTypeString);
            // 获取根节点 cas:serviceResponse
            Element rootElement = document.getRootElement();
            // 解析成功和失败节点
            Element successElement = rootElement.element("authenticationSuccess");
            Element errorElement = rootElement.element("authenticationFailure");

            if (errorElement != null || successElement == null) {
                return R.error("统一身份登录失败,ticket 错误" + errorElement.getData());
            }

            // 解析XML获取学号，姓名，人员类别
            String name = successElement.element("attributes").element("name").getText();
            String type = successElement.element("attributes").element("type").getText();
            String employeeNumber = successElement.element("attributes").element("employeeNumber")
                    .getText();
            if (employeeNumber == null || employeeNumber.isEmpty()) {
                return R.error("获取身份认证信息失败");
            }
            // 检测账号是否存在，不存在则创建
            // 密码默认为学号+123， 例如：2021211161+123
            User user = userService.loadUserByUsername(employeeNumber);
            if (user == null) {
                String password = employeeNumber + "+123";
                User newUser = new User(employeeNumber, password);
                newUser.setNickname(name);
                //  note: 如何类型没有默认用普通学生身份
                if (type == null || type.isBlank()) {
                    type = "L0102";
                }
                newUser.setUserType(type);
                userService.createUser(newUser);

                Map<String, Object> tokens = userService.generateTokens(newUser.getUserId());
                userService.setTokenCookies(response, tokens);

                return R.ok("注册并登录成功", tokens);
            }
            Map<String, Object> tokens = userService.generateTokens(user.getUserId());
            userService.setTokenCookies(response, tokens);
            return R.ok("登录成功", tokens);
        } catch (Exception e) {
            return R.error("统一身份登录失败" + e.getMessage());
        }
    }

    private  Map<String, Object> casLoginProcess(String ticket,String route,HttpServletResponse response,String customPasswordSuffix) throws Exception {
       if (customPasswordSuffix == null) {
           customPasswordSuffix = "+123";
       }
       try {
           if (route == null || route.isBlank()) {
               // TODO: 使用默认路由，后续移动端应该也更改请求路由
               route = "/mobile/login";
           }
           String localBackendUrl = localFrontendUrl + route;
           String buptAuthUrl =
                   buptAuthPrefix + "/serviceValidate?service={service}&ticket={ticket}";
           Map<String, Object> ticketParams = new HashMap<>();
           ticketParams.put("service", localBackendUrl);
           ticketParams.put("ticket", ticket);
           String numberAndTypeString = httpUtils.get(buptAuthUrl, ticketParams, String.class);
           Document document = DocumentHelper.parseText(numberAndTypeString);
           // 获取根节点 cas:serviceResponse
           Element rootElement = document.getRootElement();
           // 解析成功和失败节点
           Element successElement = rootElement.element("authenticationSuccess");
           Element errorElement = rootElement.element("authenticationFailure");

           if (errorElement != null || successElement == null) {
               throw new Exception("统一身份登录失败,ticket 错误" + errorElement.getData());
           }

           // 解析XML获取学号，姓名，人员类别
           String name = successElement.element("attributes").element("name").getText();
           String type = successElement.element("attributes").element("type").getText();
           String employeeNumber = successElement.element("attributes").element("employeeNumber")
                   .getText();
           if (employeeNumber == null || employeeNumber.isEmpty()) {
               throw  new Exception("获取身份认证信息失败");
           }
           User user = userService.loadUserByUsername(employeeNumber);
           if (user == null) {
               String password = employeeNumber + customPasswordSuffix;
               User newUser = new User(employeeNumber, password);
               newUser.setNickname(name);
               //  note: 如何类型没有默认用普通学生身份
               if (type == null || type.isBlank()) {
                   type = "L0102";
               }
               newUser.setUserType(type);
               // 设置学号
               newUser.setSchoolId(employeeNumber);
               userService.createUser(newUser);

               Map<String, Object> tokens = userService.generateTokens(newUser.getUserId());
               userService.setTokenCookies(response, tokens);
               return tokens;
           }
           Map<String, Object> tokens = userService.generateTokens(user.getUserId());
           if (response != null) {
               userService.setTokenCookies(response, tokens);
           }
            return tokens;
       } catch (Exception e) {
           throw new Exception("统一身份登录失败" + e.getMessage());
       }
    }
    /*
     * 学校CAS统一身份登录
     *
     * @param ticket
     * @return com.bupt.ilink.utils.R
     * @author 黄加宇
     * @create 2024-10-30
     **/
    @MethodLog("学校CAS协议统一身份登录")
    @PostMapping("/school_cas_login")
    public R schoolCASLogin(@RequestBody UserCASDTO userCASDTO,HttpServletResponse response) {
        log.info("接口请求参数：{}",userCASDTO);
        try {
            String ticket = userCASDTO.getTicket();
            String route = userCASDTO.getRoute();
            Map<String, Object> tokens = casLoginProcess(ticket, route,response,null);
            return R.ok("登录成功", tokens);
        }catch (Exception e) {
            log.error("CAS统一身份登录失败",e);
            return R.error("统一身份登录失败" + e.getMessage());
        }
    }

    /**
     * 描述: 用户注册账号接口，创建账号和密码
     */
    @MethodLog("用户注册接口，创建账号和密码")
    @PostMapping("/register")
    public R register(@RequestBody UserDTO request) {
        String username = request.getUsername();
        String password = request.getPassword();
        if (password == null || password.isBlank()) {
            return R.error("请填写密码");
        }

        if (userService.userExists(username)) {
            return R.error("Username 已经存在");
        }
        //  校验是否是强密码
        String passwordStrength = userService.checkPasswordStrength(password);
        if (!passwordStrength.equals("TRUE")) {
            return R.error(passwordStrength);
        }
        try {
            User newUser = new User(username, password);
            //  设置用户类型，默认为学生
            newUser.setUserType("L0102");
            userService.createUser(newUser);
//            System.out.println("注册时插入技能树副本");
            String id = newUser.getUserId();
            Map<String, Object> data = new HashMap<>();
            data.put("userId", id);
            data.put("username", username);
            return R.ok("User registered successfully", data);
        } catch (Exception e) {
            return R.error("创建用户失败" + e.getMessage());
        }
    }

    /**
     * 描述: 创建/修改用户基本信息(学校，昵称，邮箱)，只能修改这三个最基础的字段，因为这是一个不安全接口
     */
    @MethodLog("创建修改用户基本信息")
    @PostMapping("/personal_register")
    public R personal_login(@RequestBody UserDTO request) {
        String username = request.getUsername();
        String schoolName = request.getSchoolName();
        String nickname = request.getNickname();
        String email = request.getEmail();
        if (schoolName == null || nickname == null || schoolName.isBlank() || nickname.isBlank()) {
            return R.error("请填写所有信息后注册");
        }

        try {
            User userDetails = userService.loadUserByUsername(username);
            if (userDetails == null) {
                return R.error("Username 找不到");
            }
            User user = userDetails;
            user.setSchoolName(schoolName);
            user.setEmail(email);
            user.setNickname(nickname);
            userService.updateById(user);
            String id = user.getUserId();
            Map<String, Object> data = new HashMap<>();
            data.put("userId", id);
            data.put("schoolName", schoolName);
            data.put("nickname", nickname);

            return R.ok("Personal information updated successfully", data);
        } catch (Exception e) {
            return R.error(e.getMessage());
        }
    }

    @MethodLog(value = "刷新")
    @PostMapping("/refresh")
    public R refresh(@CookieValue(value = "refresh_token_lf") String refreshToken,
                     HttpServletResponse response) {
        if (refreshToken == null) {
            return R.error("No refresh token found");
        }
        try {
            jwtTokenProvider.validateToken(refreshToken);
        } catch (UnauthorizedException e) {
            return R.error(e);
        } catch (Exception e) {
            return R.error(e.getMessage());
        }
        try {
            Map<String, String> accessTokenData = new HashMap<>();
            String userId = jwtTokenProvider.getUserIdFromToken(refreshToken);
            accessTokenData.put("sub", userId);
            accessTokenData.put("type", "access");
            long accessTokenExpiresIn = jwtProperties.getTokenTTL();
            String accessToken = jwtTokenProvider.createToken(accessTokenData,
                    accessTokenExpiresIn);

            Map<String, String> refreshTokenData = new HashMap<>();
            refreshTokenData.put("sub", userId);
            refreshTokenData.put("type", "refresh");
            long refreshTokenExpiresIn = jwtProperties.getRefreshTTL();
            String newRefreshToken = jwtTokenProvider.createToken(refreshTokenData,
                    refreshTokenExpiresIn);

            Map<String, Object> tokens = new HashMap<>();
            tokens.put("access_token", accessToken);
            tokens.put("refresh_token", newRefreshToken);
            tokens.put("token_type", "bearer");

            Cookie accessCookie = new Cookie("access_token_lf", accessToken);
            accessCookie.setPath("/");
            accessCookie.setHttpOnly(false);
            accessCookie.setSecure(false);
            accessCookie.setMaxAge(Math.toIntExact(jwtProperties.getTokenTTL()));
            response.addCookie(accessCookie);

            Cookie refreshCookie = new Cookie("refresh_token_lf", refreshToken);
            refreshCookie.setPath("/");
            refreshCookie.setHttpOnly(false);
            refreshCookie.setSecure(false);
            refreshCookie.setMaxAge(Math.toIntExact(jwtProperties.getRefreshTTL()));
            response.addCookie(refreshCookie);
            return R.ok("Token refreshed successfully", tokens);
        } catch (Exception e) {
            return R.error(e.getMessage());
        }
    }
    @MethodLog("返回用户完整详细信息")
    @GetMapping("/get_usermeta")// @RequestHeader("Authorization") String token
    public R getUserMeta() {
        // 获取携带token的用户个人信息
        String userId = UserContext.getUserId();
        // note: 必须传入ID才可以
        if (userId.isEmpty()) {
            return R.error("用户id不存在");
        }
        try {
            UserAuthenticationResponse response = userService.getUserAuthenticationById(userId);
            if (response == null) {
                return R.error("用户信息未找到");
            }
            return R.ok("用户信息成功召回", response);
        } catch (IllegalArgumentException e) {
            return R.error(e.getMessage());
        }
    }

    //用户信息认证写入
//    @PostMapping("/update_usermeta")
//    public R updateUsermetas(@RequestBody UserAuthenticationRequest userDTO) {
//        // 获取携带token的用户个人信息
//        String userId = UserContext.getUserId();
//        User userDetails = userService.loadUserByUserId(userId);
//        // note: 必须传入ID才可以
//        if (userDetails.getUserId().isEmpty()) {
//            return R.error("需要传入用户id");
//        }
//        try {
//            boolean isUpdated = userService.updateUserMetaById(userId, userMetaResponse);
//            if (isUpdated) {
//                return R.ok("写入个人资料成功");
//            } else {
//                log.error("Failed to update user meta for {}", user.getUserId());
//
//                return R.error("User not found or update failed");
//            }
//        }
//        catch (UnauthorizedException e) {
//            return R.error(e.getMessage());
//        }
//    }


    //更新用户封面和头像
    @MethodLog("更新用户封面和头像")
    @PutMapping("/update_user_image")
    public R updateUsermeta(
            @RequestParam(required = false) MultipartFile userCover,
            @RequestParam(required = false) MultipartFile userImage) {
        // 获取携带token的用户个人信息
        String userId = UserContext.getUserId();
        User userDetails = userService.loadUserByUserId(userId);

        // note: 必须传入ID才可以
        if (userDetails.getUserId().isEmpty()) {
            return R.error("需要传入用户id");
        }
        try {
            // note: 必须传入ID或者username才可以
//            User user = (User) userDetails;
            return userService.updateUserImageById(userDetails, userCover, userImage);
        } catch (Exception e) {
            return R.error("更新失败");
        }

    }
    @MethodLog(value = "加载用户元数据信息")
    @GetMapping("/load_user_meta")
    public R loadUserMeta(@RequestParam List<String> userIds) {
        try {
            List<User> users = new ArrayList<>();
            for (String userId : userIds) {
                User user = userService.loadUserByUserId(userId);
                if (user == null) {
                    return R.error("User not found");
                }
                users.add(user);
            }
            return R.ok(users);
        } catch (Exception e) {
            return R.error(e.getMessage());
        }
    }
    @MethodLog(value = "前端获取当前用户信息")
    @GetMapping("/whoami_frontend")
    public R whoamiFrontend() {
        String userId = UserContext.getUserId();
        if (userId == null || userId.isBlank()) {
            return R.error("用户id错误，找不到");
        }
        try {
            UserMetaResponse userDetails = userService.getUserMetaById(userId);
            if (userDetails == null) {
                return R.error("用户未找到");
            }
            return R.ok(userDetails);
        } catch (Exception e) {
            return R.error("获取用户基本信息失败");
        }
    }
    @MethodLog(value = "获取指定用户信息")
    @GetMapping("/whoami")
    public R whoami(@RequestParam("userId") String userId) {
        if (userId == null || userId.isBlank()) {
            return R.error("用户id错误，找不到");
        }
        try {
            UserMetaResponse user = userService.getUserMetaById(userId);
            if (user == null) {
                return R.error("用户未找到");
            }
            return R.ok("获取用户", user);
        } catch (Exception e) {
            return R.error(e.getMessage());
        }
    }

    // 写入个人资料
    @MethodLog(value = "更新用户个人资料")
    @PutMapping("/update_usermeta")
    public R updateUsermeta(@RequestBody UserAuthenticationRequest userDTO) {
        // 获取携带token的用户个人信息
        String userId = UserContext.getUserId();
        try {
            boolean isUpdated = userService.updateUserMetaById(userId, userDTO);
            if (isUpdated) {
                return R.ok("写入个人资料成功");
            } else {
                log.error("Failed to update user meta for {}",userId);
                return R.error("User not found or update failed");
            }
        } catch (UnauthorizedException e) {
            return R.error(e.getMessage());
        }
    }

    //导入收集表，批量更新用户信息
    @MethodLog(value = "批量更新用户信息")
    @PostMapping("/update_usermeta_batch")
    public R updateUsermetaBatch(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return R.error("CSV 文件不能为空");
        }
        try {
//            boolean isUpdated = userService.updateUserMetaByFile(file);
            boolean isUpdated =userMessageExportService.importUserMessageTable(file);
            if (isUpdated) {
                return R.ok("导入用户收集数据，并批量更新用户资料成功");
            } else {
                return R.error("User not found or update failed");
            }
        } catch (UnauthorizedException e) {
            return R.error(e.getMessage());
        }
    }

    //根据学号、姓名查找用户，用于微场景添加出品人
    @MethodLog(value = "根据学号、姓名查找用户")
    @GetMapping("/search_user_by_id_and_name")
    public R searchUserBySchoolIdAndName(@RequestParam("query") String query) {
        try {
            List<User> users = userService.searchUserBySchoolIdAndName(query);
            return R.ok("查询用户成功", users);
        } catch (Exception e) {
            return R.error("查询用户失败", e.getMessage());
        }
    }

    @MethodLog(value = "根据姓名模糊匹配查找用户")
    @GetMapping("/search_user_by_name")
    public R searchUserByName(@RequestParam("query") String query) {
        try {
            List<User> users = userService.searchUserByRealName(query);
            return R.ok("查询用户成功", users);
        } catch (Exception e) {
            return R.error("查询用户失败", e.getMessage());
        }
    }

    // 根据用户id和SceneId，获取用户是否具有创建、查看、编辑场景权限
    @MethodLog(value = "根据用户id和SceneId，获取用户是否具有创建、查看、编辑场景权限")
    @GetMapping("/check_user_scene_permission")
    public R checkUserScenePermission(@RequestParam("userId") String userId,
                                       @RequestParam(value = "sceneId", required = false) Long sceneId) {
        try {
            Map<String, Boolean> permissions = userService.checkUserScenePermission(userId, sceneId);
            return R.ok("获取用户场景权限成功", permissions);
        } catch (Exception e) {
            return R.error("获取用户场景权限失败", e.getMessage());
        }
    }

    /**
     * OAuth2.0 授权端点
     */
    @MethodLog("OAuth2.0授权")
    @GetMapping("/oauth/authorize")
    public R authorize(@RequestParam("response_type") String responseType,
                      @RequestParam("client_id") String clientId,
                      @RequestParam("redirect_uri") String redirectUri,
                      @RequestParam("scope") String scope,
                      @RequestParam("state") String state,
                      @RequestParam("ticket") String ticket,
                      @RequestParam("route") String route,
                       HttpServletResponse response) {

        // 验证client_id是否有效

        if (!oauth2Properties.getClientIds().contains(clientId)) {
            return R.error("无效的client_id");
        }

        // 验证redirect_uri是否在允许列表中
        if (!oauth2Properties.getRedirectUris().contains(redirectUri)) {
            return R.error("无效的redirect_uri");
        }

        // 验证response_type是否为code
        if (!"code".equals(responseType)) {
            return R.error("不支持的response_type");
        }

        try {
            // 验证CAS登录
            Map<String, Object> tokens = casLoginProcess(ticket, route, response, "+#BMCm$5");
            String accessToken = (String) tokens.get("access_token");
            if (accessToken == null || accessToken.isEmpty()) {
                return R.error("CAS统一身份登录失败");
            }

            // 从accessToken中获取userId
            String userId = jwtTokenProvider.getUserIdFromToken(accessToken);
            if (userId == null || userId.isEmpty()) {
                return R.error("无法获取用户信息");
            }

            // 生成授权码并关联用户ID
            String authCode = userService.generateAuthorizationCode(clientId, scope, state, userId);

            // 构建重定向URL
            String redirectUrl = String.format("%s?code=%s&state=%s",
                redirectUri, authCode, state);

            Map<String, String> result = new HashMap<>();
            result.put("redirect_url", redirectUrl);

            return R.ok("授权成功", result);
        } catch (Exception e) {
            log.error("授权失败", e);
            return R.error("授权失败:" + e.getMessage());
        }
    }

    /**
     * OAuth2.0 令牌端点
     * 用授权码换取访问令牌
     */
    @MethodLog("OAuth2.0获取令牌")
    @PostMapping("/oauth/token")
    public R token(@RequestParam("code") String code,
                   @RequestParam("client_id") String clientId,
                   @RequestParam("client_secret") String clientSecret) {

        // 验证客户端凭证
        if (!oauth2Properties.getClientIds().contains(clientId) ||
            !clientSecret.equals(oauth2Properties.getClientSecrets().get(clientId))) {
            return R.error("无效的客户端凭证");
        }

        // 验证授权码
        try {
            // 验证授权码是否有效
            if (!userService.validateAuthorizationCode(code)) {
                return R.error("无效的授权码");
            }

            // 获取用户信息
            String userId = userService.getUserIdFromAuthCode(code);

            // 将用户基本信息直接返回给客户端
            UserMetaResponse response = userService.getUserMetaById(userId);

            return R.ok("令牌获取成功", response);
        } catch (Exception e) {
            return R.error("令牌获取失败:" + e.getMessage());
        }
    }

    @MethodLog("oauth2.0基于密码获取令牌")
    @PostMapping("/oauth/authorize-by-pwd")
    public R authorizeByPwd(@RequestBody UserDTO request, HttpServletResponse response) {
        // 验证客户端凭证
        String clientId = request.getClientId();
        if(!oauth2Properties.getClientIds().contains(clientId)) {
            return R.error("无效的客户端凭证");
        }
        // 验证redirectUri是否在允许列表中
        String redirectUri = request.getRedirectUri();
        if (!oauth2Properties.getRedirectUris().contains(redirectUri)) {
            return R.error("无效的redirect_uri");
        }
        // 验证response_type是否为code
        String responseType = request.getResponseType();
        if (!"code".equals(responseType)) {
            return R.error("不支持的response_type");
        }
        // 输入用户名和加密后的密码获取授权码
        String username = request.getUsername();
        String password = request.getPassword();
        if (password == null || password.isBlank()) {
            return R.error("请填写密码");
        }

        try {
            User user = userService.loadUserByUsername(username);
            if (user == null) {
                return R.error("Username not found");
            }
            // 密码解密
            String decryptedPassword = RSAUtils.decrypt(password, keyPair.getPrivate());
            //  校验用户名和密码
            if (!userService.checkUsernameAndPassword(username, decryptedPassword)) {
                return R.error("密码错误");
            }
            //  用户密码验证成功
            String userId = user.getUserId();
            //  生成授权码并关联用户ID
            String scope = request.getScope();
            //  登录的不需要state 参数，所以直接使用空字符串就行
            String state = request.getState();
            String authCode = userService.generateAuthorizationCode(clientId, scope, state, userId);


            // 构建重定向URL
            String redirectUrl = String.format("%s?code=%s&state=%s",
                    redirectUri, authCode, state);

            Map<String, String> result = new HashMap<>();
            result.put("redirect_url", redirectUrl);

            return R.ok("授权成功", result);
        } catch (Exception e) {
            return R.error(e.getMessage());
        }
    }

    @MethodLog("链接登录")
    @PostMapping("/oauth2/authorize")
    public R newLogin(@RequestParam("phone") String phone,
                      @RequestParam("realname") String realname,
                      @RequestParam("timestamp") String timestamp,
                      HttpServletResponse response) throws Exception {

        // 校验timestamp是否在当前时间前后10分钟内
        long currentTime = System.currentTimeMillis();
        long providedTime = Long.parseLong(timestamp) * 1000; // 转换为毫秒级时间戳
        if (Math.abs(currentTime - providedTime) > 10 * 60 * 1000) { // 10分钟的毫秒数
            return R.error("时间戳无效，必须在当前时间前后10分钟内");
        }

        String password = phone + "+123"; // 密码为手机号 + "123"
        try {
            // 检查用户是否存在
            User existingUser = userService.loadUserByUsername(phone);
            if (existingUser == null) {
                User newUser = new User(phone, password);
                newUser.setRealname(realname);
                newUser.setUserType("L0102");
                userService.createUser(newUser);

                Map<String, Object> tokens = userService.generateTokens(newUser.getUserId());
                userService.setTokenCookies(response, tokens);
                return R.ok("注册并登录成功", tokens);
            }
            Map<String, Object> tokens = userService.generateTokens(existingUser.getUserId());
            existingUser.setRealname(realname);
            if (response != null) {
                userService.setTokenCookies(response, tokens);
            }
            return R.ok("登录成功", tokens);
        }
        catch (Exception e) {
            log.error("链接登录失败",e);
            return R.error("链接登录失败" + e.getMessage());
        } 
    }
}